#pragma once
#include <iostream>
#include <string>
#include <unordered_map>
#include <sstream>
#include "Logger.hpp"

const static std::string sep1 = " ";
const static std::string sep2 = ": ";
const static std::string linesep = "\r\n";
const static std::string argsep = "?";
const static std::string root = "./wwwroot";      // web根目录
const static std::string homehtml = "index.html"; // 网站首页

// 自定义http协议
// 请求
// 向通过浏览器向服务器发送请求，浏览器作为客户端，因此帮助我们做了序列化的工作
// 所以只需要反序列化
class HttpRequest
{
private:
    // 这里传的参数是一个输入输出参数，所以只用引用，不需要加const
    std::string ReadOneLine(std::string &reqstr, bool *status)
    {
        auto pos = reqstr.find(linesep);
        if (pos == std::string::npos)
        {
            *status = false;
            return std::string();
        }
        *status = true;
        std::string line = reqstr.substr(0, pos);
        reqstr.erase(0, pos + linesep.size());
        return line;
    }
    void SegmentReqLine(const std::string &linstr)
    {
        std::stringstream ss(linstr);
        ss >> _method >> _uri >> _http_version;
    }
    void BuildKV(const std::string &linestr, std::string *k, std::string *v)
    {
        auto pos = linestr.find(sep2);
        if (pos == std::string::npos)
        {
            *k = *v = std::string();
            return;
        }
        *k = linestr.substr(0, pos);
        *v = linestr.substr(pos + sep2.size());
    }

public:
    HttpRequest() {}
    // 反序列化就是对字符串进行截取，然后填充结构体中的字段
    // 我们不关心浏览器怎么处理字符串，我们把字符串视为已经拼接好的
    // 我们只需要对字符串进行分割
    bool DeSerialize(std::string &reqstr)
    {
        // 1.提取一行字符串
        bool status=true;
        std::string linestr = ReadOneLine(reqstr, &status);
        LOG(LogLevel::DEBUG) << linestr;
        if (!status)
        {
            return false;
        }
        // 2.将第一行字符串进行分割，填充属性
        SegmentReqLine(linestr);
        while (true)
        {
            status=true;
            linestr = ReadOneLine(reqstr, &status);
            if (status && !linestr.empty())
            {
                std::string k, v;
                BuildKV(linestr, &k, &v);
                if (k.empty() || v.empty())
                {
                    continue;
                }
                _req_hander.emplace(std::make_pair(k, v));
            }
            else if (status)
            {
                _blank_line = linesep;
                break;
            }
            else
            {
                LOG(LogLevel::ERROR) << "非法请求";
                break;
            }
        }

        // 由于服务器需要根据路径来访问不同的网页，所以我们需要指定资源的访问路径
        _path = root;
        _path += _uri;
        if (_uri == "/")
        {
            _path += homehtml;
        }
        LOG(LogLevel::DEBUG) << "path: " << _path;
        // GET方法会把诸如账号密码的内容以？为分隔符，跟在路径后面
        // 所以需要对路径进行再次查找并分割
        if (_method == "GET")
        {
            auto pos = _path.find(argsep);
            if (pos != std::string::npos)
            {
                _req_body = _path.substr(pos + argsep.size());
                _path = _path.substr(0, pos);
            }
        }
        else if (_method == "POST")
        {
            _req_body = reqstr;
        }
        return true;
    }
    std::string Path()
    {
        return _path;
    }
    ~HttpRequest() {}

private:
    std::string _method;
    std::string _uri;
    std::string _http_version;
    std::unordered_map<std::string, std::string> _req_hander;
    std::string _blank_line;
    std::string _req_body;
    std::string _path;
};

// 响应
// 服务器响应浏览器的请求，需要将处理结果返回，所以要进行序列化
// 浏览器会帮我们反序列化
class HttpResponse
{
public:
    HttpResponse() : _http_version("HTTP/1.1"), _blank_line(linesep)
    {
    }
    // 序列化就是字符串拼接，将结构化的数据拼接成大字符串
    std::string Serialize()
    {
        std::stringstream ss;
        ss << _code;
        std::string respstr = _http_version + sep1 + ss.str() + sep1 + _code_dsc + linesep;
        if (!_resp_body.empty())
        {
            std::string len = std::to_string(_resp_body.size());
            SetHander("Content-Length", len);
        }
        for (auto &e : _resp_hander)
        {
            std::string line = e.first + sep2 + e.second + linesep;
            respstr += line;
        }
        respstr += _blank_line;
        respstr += _resp_body;
        return respstr;
    }
    bool ReadContent(const std::string &path)
    {
        // ⼀份简单的读取⼆进制⽂件的代码
        std::ifstream in(path, std::ios::binary);
        if (!in.is_open())
            return false;
        in.seekg(0, in.end);
        int filesize = in.tellg();
        in.seekg(0, in.beg);

        _resp_body.resize(filesize);
        in.read((char *)_resp_body.c_str(), filesize);
        // std::vector<char> content(filesize);
        // in.read(content.data(), filesize);
        in.close();
        return true;
    }
    bool SetHander(const std::string &key, const std::string &value)
    {
        _resp_hander[key] = value;
        return true;
    }
    void SetCode(int code, const std::string &dsc)
    {
        _code = code;
        _code_dsc = dsc;
    }
    ~HttpResponse() {}

private:
    std::string _http_version;
    std::string _code;
    std::string _code_dsc;
    std::unordered_map<std::string, std::string> _resp_hander;
    std::string _blank_line;
    std::string _resp_body;
};

class Http
{
public:
    Http() {}
    std::string HanderRequst(std::string &reqstr)
    {
        HttpRequest req;
        std::string respstr;
        if (req.DeSerialize(reqstr))
        {
            HttpResponse resp;
            resp.ReadContent(req.Path());
            resp.SetCode(200, "OK");
            resp.SetHander("Content-Type", "text/html");
            respstr=resp.Serialize();
        }
        return respstr;
    }
    ~Http() {}

private:
};

//总结：http协议
//1.服务端负责反序列化，客户端负责序列化
//2.反序列化：对  